package com.bzy.common.util.local;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

public class ThreadLocalUtil {

	private static final Logger log = LoggerFactory.getLogger(ThreadLocalUtil.class);

	public static final String SECURITY_MANAGER_KEY = ThreadLocalUtil.class.getName() + "_SECURITY_MANAGER_KEY";
	public static final String SUBJECT_KEY = ThreadLocalUtil.class.getName() + "_SUBJECT_KEY";
	
	public static void setRunTime(long time) {
		put("RunTime", time);
	}

	public static Long getRunTime() {
		return (Long) get("RunTime");
	}

	public static void setResponseObj(Object responseObj) {
		put("ResponseObj", responseObj);
	}

	public static Object getResponseObj() {
		return get("ResponseObj");
	}

	public static void setExceptionString(String exceptionString) {
		put("ExceptionString", exceptionString);
	}

	public static String getExceptionString() {
		return (String) get("ExceptionString");
	}

	public static void setIsAuthenticated(Boolean isAuthenticated) {
		put("IsAuthenticated", isAuthenticated);
	}

	public static Boolean getIsAuthenticated() {
		return (Boolean) get("IsAuthenticated");
	}

	/*** 存放用户id **/
	public static void setSessionUserId(String userId) {
		put("SessionUserId", userId);
	}

	/*** 获取用户id **/
	public static String getSessionUserId() {
		return ObjectUtils.defaultIfNull((String) get("SessionUserId"), "");
	}

	/*** 存放后台登录用户id **/
	public static void setSessionAccountUserId(String userId) {
		put("SessionAccountUserId", userId);
	}

	/*** 获取后台登录用户id **/
	public static String getSessionAccountUserId() {
		return ObjectUtils.defaultIfNull((String) get("SessionAccountUserId"), "");
	}

	/**
	 * Private internal log instance.
	 */

	private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();

	/**
	 * Default no-argument constructor.
	 */
	protected ThreadLocalUtil() {
	}

	public static Map<Object, Object> getResources() {
		if (resources.get() == null) {
			return Collections.emptyMap();
		} else {
			return new HashMap<Object, Object>(resources.get());
		}
	}

	public static void setResources(Map<Object, Object> newResources) {
		if (CollectionUtils.isEmpty(newResources)) {
			return;
		}
		ensureResourcesInitialized();
		resources.get().clear();
		resources.get().putAll(newResources);
	}

	private static Object getValue(Object key) {
		Map<Object, Object> perThreadResources = resources.get();
		return perThreadResources != null ? perThreadResources.get(key) : null;
	}

	private static void ensureResourcesInitialized() {
		if (resources.get() == null) {
			resources.set(new HashMap<Object, Object>());
		}
	}

	public static Object get(Object key) {
		if (log.isTraceEnabled()) {
			String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";
			log.trace(msg);
		}

		Object value = getValue(key);
		if ((value != null) && log.isTraceEnabled()) {
			String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + key + "] "
					+ "bound to thread [" + Thread.currentThread().getName() + "]";
			log.trace(msg);
		}
		return value;
	}

	public static void put(Object key, Object value) {
		if (key == null) {
			throw new IllegalArgumentException("key cannot be null");
		}

		if (value == null) {
			remove(key);
			return;
		}

		ensureResourcesInitialized();
		resources.get().put(key, value);

		if (log.isTraceEnabled()) {
			String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + key + "] to thread "
					+ "[" + Thread.currentThread().getName() + "]";
			log.trace(msg);
		}
	}

	public static Object remove(Object key) {
		Map<Object, Object> perThreadResources = resources.get();
		Object value = perThreadResources != null ? perThreadResources.remove(key) : null;

		if ((value != null) && log.isTraceEnabled()) {
			String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + key + "]"
					+ "from thread [" + Thread.currentThread().getName() + "]";
			log.trace(msg);
		}

		return value;
	}

	public static void remove() {
		resources.remove();
	}

	public static SecurityManager unbindSecurityManager() {
		return (SecurityManager) remove(SECURITY_MANAGER_KEY);
	}

	public static void bind(Object key, Object value) {
		if (value != null) {
			put(key, value);
		}
	}

	public static Object unbind(Object key) {
		return remove(key);
	}

	private static final class InheritableThreadLocalMap<T extends Map<Object, Object>>
			extends InheritableThreadLocal<Map<Object, Object>> {
		@SuppressWarnings({ "unchecked" })
		protected Map<Object, Object> childValue(Map<Object, Object> parentValue) {
			if (parentValue != null) {
				return (Map<Object, Object>) ((HashMap<Object, Object>) parentValue).clone();
			} else {
				return null;
			}
		}
	}

}
